package com.tjmc.nsia.core.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tjmc.nsia.core.cache.MemoryCache;
import com.tjmc.nsia.core.config.CaptchaConfig;
import com.tjmc.nsia.core.constant.Constants;
import com.tjmc.nsia.core.constant.ErrorCodeEnum;
import com.tjmc.nsia.core.dao.entity.NsiaChatSession;
import com.tjmc.nsia.core.dao.entity.NsiaMenu;
import com.tjmc.nsia.core.dao.entity.NsiaUser;
import com.tjmc.nsia.core.dao.mapper.NsiaUserMapper;
import com.tjmc.nsia.core.dto.resp.NsiaUserExtend;
import com.tjmc.nsia.core.exception.BusinessException;
import com.tjmc.nsia.core.exception.CaptchaException;
import com.tjmc.nsia.core.exception.CaptchaExpireException;
import com.tjmc.nsia.core.schedule.AsyncFactory;
import com.tjmc.nsia.core.schedule.AsyncManager;
import com.tjmc.nsia.core.service.NsiaChatService;
import com.tjmc.nsia.core.service.NsiaChatSessionService;
import com.tjmc.nsia.core.service.NsiaMenuService;
import com.tjmc.nsia.core.service.NsiaUserService;
import com.tjmc.nsia.core.utils.CommonUtils;
import com.tjmc.nsia.core.utils.IpUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author Luc
 * @since 2024/06/03
 */
@Service
public class NsiaUserServiceImpl extends ServiceImpl<NsiaUserMapper, NsiaUser> implements NsiaUserService {

    @Autowired
    private CaptchaConfig captchaConfig;

    @Autowired
    private NsiaUserMapper nsiaUserMapper;

    @Autowired
    private NsiaChatSessionService nsiaChatSessionService;

    @Autowired
    private NsiaChatService nsiaChatService;

    @Autowired
    private NsiaMenuService nsiaMenuService;


    @Override
    public SaTokenInfo login(String username, String password, String code, String uuid) {
        validateCaptcha(username, code, uuid);
        if(StringUtils.hasText(username) && StringUtils.hasText(password)) {
            NsiaUser nsiaUser = nsiaUserMapper.selectOne(new QueryWrapper<NsiaUser>().eq("username", 	username.trim()).eq("password", DigestUtil.md5Hex(password.trim())));
            if(!Objects.isNull(nsiaUser)) {
                recordLoginInfo(nsiaUser.getId());
                StpUtil.login(nsiaUser.getId());
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, "用户登陆成功！"));
                return StpUtil.getTokenInfo();
            } else {
                throw new BusinessException(ErrorCodeEnum.USER_OR_PASSWORD_ERROR);
            }
        } else {
            throw new BusinessException(ErrorCodeEnum.USER_OR_PASSWORD_ERROR);
        }
    }

    @Override
    public void validateCaptcha(String username, String code, String uuid) {
        boolean captchaEnabled = captchaConfig.selectCaptchaEnabled();
        if (captchaEnabled) {
            String verifyKey = Constants.CAPTCHA_CODE_KEY + CommonUtils.nvl(uuid, "");
            String captcha = (String) MemoryCache.get(verifyKey);
            if (Objects.isNull(captcha)) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, ErrorCodeEnum.USER_VERIFY_CODE_EXPIRE.getMessage()));
                throw new CaptchaExpireException();
            }
            MemoryCache.remove(verifyKey);
            if (!code.equalsIgnoreCase(captcha)) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, ErrorCodeEnum.USER_VERIFY_CODE_ERROR.getMessage()));
                throw new CaptchaException();
            }
        }
    }

    @Override
    public NsiaUserExtend getLoginUser() {
        Long userId = StpUtil.getLoginIdAsLong();
        if(!Objects.isNull(userId)) {
            NsiaUser nsiaUser = nsiaUserMapper.selectById(userId);
            List<NsiaMenu> nsiaMenus = nsiaMenuService.getMenusByUserId(userId);
            NsiaUserExtend nsiaUserExtend = new NsiaUserExtend();
            BeanUtils.copyProperties(nsiaUser, nsiaUserExtend);
            nsiaUserExtend.setMenus(nsiaMenus);
            return nsiaUserExtend;
        }
        return null;
    }

    @Override
    public void logout() {
        StpUtil.logout();
    }

    @Override
    public Integer refreshSession(Long userId) {
        NsiaUser nsiaUser = nsiaUserMapper.selectById(userId);
        if(!Objects.isNull(nsiaUser)) {
//            NsiaChatSession nsiaChatSession = nsiaChatSessionService.getLatest(userId);
//            if(!Objects.isNull(nsiaChatSession)) {
//                List<NsiaChat> nsiaChats = nsiaChatService.getChats(nsiaChatSession.getId());
//                if(CollectionUtil.isEmpty(nsiaChats)) {
//                    nsiaUser.setSessionId(nsiaChatSession.getId());
//                    nsiaUserMapper.updateById(nsiaUser);
//                    return nsiaChatSession.getId();
//                }
//            } else {
                NsiaChatSession nsiaChatSession = new NsiaChatSession();
                nsiaChatSession.setTitle("新对话");
                nsiaChatSession.setUserId(userId);
                nsiaChatSession.setUpdateTime(LocalDateTime.now());
                nsiaChatSessionService.save(nsiaChatSession);
                nsiaUser.setSessionId(nsiaChatSession.getId());
                nsiaUserMapper.updateById(nsiaUser);
                return nsiaChatSession.getId();
//            }
        }
        return -1;
    }

    @Override
    public List<NsiaChatSession> getChatSessions(Long userId) {
        QueryWrapper<NsiaChatSession> queryWrapper = new QueryWrapper<NsiaChatSession>().orderByDesc("update_time");
        if(!Objects.isNull(userId) && userId > 0) {
            queryWrapper = queryWrapper.eq("user_id", userId);
        }
        return nsiaChatSessionService.list(queryWrapper);
    }

    @Override
    public void clearSessions(Long userId) {
        if(!Objects.isNull(userId) && userId > 0) {
            nsiaChatSessionService.deleteChatSessions(userId);
            NsiaUser nsiaUser = nsiaUserMapper.selectById(userId);
            if(!Objects.isNull(nsiaUser)) {
                nsiaUser.setSessionId(0);
                nsiaUser.setUpdateTime(LocalDateTime.now());
                nsiaUserMapper.updateById(nsiaUser);
            }
        }
    }

    @Override
    public SaTokenInfo wxLogin(String openid, String sessionKey) {
        if(StringUtils.hasText(openid) && StringUtils.hasText(sessionKey)) {
            NsiaUser nsiaUser = nsiaUserMapper.selectOne(new QueryWrapper<NsiaUser>().eq("openid", openid));
            if(Objects.isNull(nsiaUser)) {
                NsiaUser newUser = new NsiaUser();
                newUser.setUsername("User");
                newUser.setNickname("用户");
                newUser.setOpenid(openid);
                newUser.setSessionKey(sessionKey);
                nsiaUserMapper.insert(newUser);
                newUser.setUsername("User" + String.format("%03d", newUser.getId()));
                newUser.setPassword(SaSecureUtil.md5("User" + String.format("%03d", newUser.getId())));
                newUser.setNickname("用户" + String.format("%03d", newUser.getId()));
                nsiaUserMapper.updateById(newUser);
                nsiaMenuService.addMenusByUserId(null, newUser.getId());
                nsiaUser = newUser;
            }
            recordLoginInfo(nsiaUser.getId());
            StpUtil.login(nsiaUser.getId());
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(openid, Constants.LOGIN_SUCCESS, "微信用户登陆成功！"));
            return StpUtil.getTokenInfo();
        } else {
            throw new BusinessException(ErrorCodeEnum.WX_OPENID_OR_SESSIONKEY_ERROR);
        }
    }

    public void recordLoginInfo(Long userId) {
        NsiaUser nsiaUser = new NsiaUser();
        nsiaUser.setId(userId);
        nsiaUser.setLoginIp(IpUtils.getIpAddr());
        nsiaUser.setLoginTime(LocalDateTime.now());
        this.saveOrUpdate(nsiaUser);
    }
}
